/*
 * Copyright the original author or authors.
 * 
 * Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *	  http://www.mozilla.org/MPL/MPL-1.1.html
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 package com.googlecode.milib.display.service {
	import com.googlecode.milib.base.MLBroadcastClass;
	import com.googlecode.milib.util.MLMCUtil;

	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.display.FrameLabel;
	import flash.display.InteractiveObject;
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.text.TextField;
	import flash.utils.Dictionary;

	/**
	 * @author Marek Brun
	 */
	public class MLMC extends MLBroadcastClass {
		
		private static const servicedObjects : Dictionary = new Dictionary(true);
		public var _mc:MovieClip;		
		private var targetFrame:int;
		private var labelNameAndFrameNumber:Array;

		public function MLMC(access:Private, mc:MovieClip) {
			_mc=mc;
		}
		
		public function get mc():MovieClip { return _mc; }
		
		public function playTo(targetFrame:uint):void {
			this.targetFrame=targetFrame;
			_mc.stop();
			if(_mc.currentFrame==this.targetFrame){
				endPlayTo();
			}else{
				_mc.addEventListener(Event.ENTER_FRAME, onEnterFrameForStepToTargetFrame, false, 0, true);
			}
		}
		public function playToByLabel(targetLabel:String):void {
			playTo(MLMCUtil.getFrameByLabel(mc, targetLabel));
		}
		public function playToByTotalFrames(targetFramesN01:Number):void {
			playTo(MLMCUtil.getFrameByTotalFrames01(mc, targetFramesN01));
		}
		
		public function getFrameByTotalFrames01(n01:Number):Number {
			return 1+int(n01*(_mc.totalFrames-1));
		}
		
		private function stepToTargetFrame():void {
			var cf:Number=_mc.currentFrame;
			if(cf<targetFrame){
				_mc.nextFrame();
			}else if(cf>targetFrame){
				_mc.prevFrame();
			}else{
				endPlayTo();
			}
		}
		
		public function gotoAndStop(frame:*):void {
			endPlayTo();
			_mc.gotoAndStop(frame);
		}
		
		public function gotoAndPlay(frame:*):void {
			endPlayTo();
			_mc.gotoAndPlay(frame);
		}
		
		private function endPlayTo():void {
			_mc.removeEventListener(Event.ENTER_FRAME, onEnterFrameForStepToTargetFrame);
			_mc.stop();
			targetFrame=NaN;
		}
		
		/**
		 * @param targetName can be also sub object, ex: 'box.border.left'
		 */
		public function getChildByTargetName(targetName:String):DisplayObject {
			//checking if child is not DisplayObjectContainer
			if(_mc.getChildByName(targetName) && !(_mc.getChildByName(targetName)is DisplayObjectContainer)){
				return _mc.getChildByName(targetName);
			}
			
			var instanceNames:Array=targetName.split('.');
			var mcIn:DisplayObjectContainer=mc;
			while(instanceNames.length){
				if(mcIn.getChildByName(instanceNames[0])){
					if(mcIn.getChildByName(instanceNames[0]) is DisplayObjectContainer){
						mcIn=DisplayObjectContainer(mcIn.getChildByName(instanceNames.shift()));
					}else{
						return mcIn.getChildByName(instanceNames.shift());
					}
				}else{
					return null;
				}
			}
			return mcIn;
		}
		
		public function getMC(targetName:String):MovieClip {
			if(!targetName){
				throw new Error('targetName is:'+targetName);
			}
			var findedMC:MovieClip=MovieClip(getChildByTargetName(targetName));
			if(findedMC){
				return findedMC;
			}else{
				throw new Error('Can\'t get child mc "'+targetName+'" from "'+mc.name+'.'+mc.parent.name+'.'+mc.parent.parent.name+'"');
			}
			return null;
		}
		
		public function getMLMC(targetName:String):MLMC {
			return MLMC.forInstance(getMC(targetName));
		}
		
		public function getMLButton(targetName:String):MLButton {
			return MLButton.forInstance(InteractiveObject(getChildByTargetName(targetName)));
		}
		
		public function getTextField(targetName:String):TextField {
			return TextField(getChildByTargetName(targetName));
		}
		
		public function getMLTextField(targetName:String):MLTextField {
			return MLTextField.forInstance(getTextField(targetName));
		}
		
		public function gotInstanceByDOCAndName(parentMC:DisplayObjectContainer, name:String):Boolean {
			return Boolean(parentMC.getChildByName(name));
		}
		
		public function gotInstanceByName(name:String):Boolean {
			return Boolean(_mc.getChildByName(name));
		}
		
		public function getFrameNumberByNumberOrLabelName(frame:*):Number {
			if(frame is Number){
				return Number(frame);
			}else{
				return getFrameNumberByLabelName(String(frame));
			}
		}
		
		public function getFrameNumberByLabelName(labelName:String):Number {
			if(!labelNameAndFrameNumber){
				labelNameAndFrameNumber=[];
				var i:uint;
				var loopLabel:FrameLabel;
				for(i=0;i<_mc.currentLabels.length;i++){
					loopLabel=_mc.currentLabels[i];
					labelNameAndFrameNumber[loopLabel.name]=loopLabel.frame;
				}
			}
			return labelNameAndFrameNumber[labelName];
		}
		
		public function gotInstance(targetName:String):Boolean {
			var instanceNames:Array=targetName.split('.');
			var mcIn:DisplayObjectContainer=mc;
			while(instanceNames.length){
				if(gotInstanceByDOCAndName(mcIn, instanceNames[0])){
					if(mcIn.getChildByName(instanceNames[0]) is DisplayObjectContainer){
						mcIn=DisplayObjectContainer(mcIn.getChildByName(instanceNames.shift()));
					}else if(instanceNames.length>1){
						return false;
					}else{
						return true;
					}
				}else{
					return false;
				}
			}
			return true;
		}
		
		public static function forInstance(mc:MovieClip):MLMC {
			if(mc==null){
				throw Error("Value of passed argument 'mc' is null");
				return;
			}
			if(servicedObjects[mc]){
				return servicedObjects[mc];
			}else{
				servicedObjects[mc]=new MLMC(null, mc);
				return servicedObjects[mc];
			}
		}
		
		protected function onEnterFrameForStepToTargetFrame(event:Event):void {
			stepToTargetFrame();
		}
		
		public function getMCSByPrefix(prefix:String, isCount:Boolean=true):Array {
			var i:uint=0, arr:Array=[];
			while(gotInstance(prefix+i)){
				arr.push(getMC(prefix+i));
				i++;
			}
			return arr;
		}
	}
}

internal class Private {}